package com.cqhfan.authservice.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.cqhfan.authservice.config.JwtProperties;
import com.cqhfan.authservice.service.TokenService;
import com.cqhfan.core.constans.BizConstants;
import com.cqhfan.core.domain.dto.UserAuthDTO;
import com.cqhfan.core.utils.JwtUtil;
import com.cqhfan.pojo.user.vo.UserLoginVO;
import com.cqhfan.redis.constants.RedisConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 眭传洪
 * @create 2025-07-26 0:00
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TokenServiceImpl implements TokenService {

    private final JwtProperties jwtProperties;

    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public String createAccessToken(Map<String, Object> map) {
        return JwtUtil.createToken(map, jwtProperties.getPrivateKey(), jwtProperties.getAccessTokenTtl());
    }

    @Override
    public String createRefreshToken(Map<String, Object> map, UserAuthDTO loginAuthBody) {
        // 获取refreshToken有效期
        Long ttl = jwtProperties.getRefreshTokenTtl();
        // 创建token
        String token = JwtUtil.createToken(map, jwtProperties.getPrivateKey(), ttl);
        // 将数据也保存到长token刷新token的时候把数据同步过去 使用md5加密是为了让key短一点
        String key = getRefreshTokenKey(token);
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(loginAuthBody),
                jwtProperties.getRefreshTokenTtl(), TimeUnit.MINUTES);
        return token;
    }

    @Override
    public UserLoginVO refreshToken(String refreshToken) {
        if (StrUtil.isBlank(refreshToken)) {
            return null;
        }

        // 解析token
        Map<String, Object> map = JwtUtil.parseToken(refreshToken, jwtProperties.getPublicKey());
        if (map == null) {
            // token无效
            return null;
        }

        // 从token获取数据
        String key = getRefreshTokenKey(refreshToken);
        String loginInfoStr = stringRedisTemplate.opsForValue().get(key);
        if (StrUtil.isBlank(loginInfoStr)) {
            // 已过期 需要重新登录了
            return null;
        }

        // redis删除这个token
        stringRedisTemplate.delete(key);

        // 将数据放到当前的uuid
        UserAuthDTO userAuthInfo = JSONUtil.toBean(loginInfoStr, UserAuthDTO.class);
        key = RedisConstants.LOGIN_CACHE_KEY_PREFIX + map.get(BizConstants.TOKEN_LOGIN_INFO);
        UserAuthDTO loginAuthBody = new UserAuthDTO();
        loginAuthBody.setUserId(userAuthInfo.getUserId());
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(loginAuthBody),
                jwtProperties.getAccessTokenTtl(), TimeUnit.MINUTES);

        // 重新生成两个token返回
        String accessToken = createAccessToken(map);
        String newRefreshToken = createRefreshToken(map, userAuthInfo);
        return UserLoginVO.builder()
                .accessToken(accessToken)
                .refreshToken(newRefreshToken)
                .build();
    }

    private String getRefreshTokenKey(String token) {
        return RedisConstants.REFRESH_TOKEN_PREFIX + SecureUtil.md5(token);
    }

    @Override
    public Long getAccessTokenTTL() {
        return jwtProperties.getAccessTokenTtl();
    }
}
